﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataSource;
using Exchange;
using CsvHelperPlus;
using System.IO;
using Strategy.Linkage;
using DataSource;
using System.IO;
using System.Data;
using Strategy.Linkage;



namespace Trader
{

    public class OrderRecord
    {
        Dictionary<string, Record> orderDict; //记录所有发出的订单
        DateTime curTime;
     
        public OrderRecord()
        {
            orderDict = new Dictionary<string, Record>();
        }
        public void AddRecord(Record rd)
        {
            if (orderDict.ContainsKey(rd.orderId))
            {
                throw new Exception("error");
            }
            orderDict[rd.orderId] = rd;
        }

        public void OnTimePulse(DateTime dt)
        {
            curTime = dt;
        }

        public DateTime GetCurrentTime()
        {
            return curTime;
        }

        public Record Get(string id)
        {
            return orderDict[id];
        }
        
        public void Update(Deal dl) //交易所反馈的
        {
            Record rd = Find(dl); // 找到发单的记录
            if (dl.type == OrderType.Cancel) //反馈的是撤销单
            {
                if(dl.isCanceled) //撤销单反馈了已撤销信息
                {
                    Record rdTarget = Get(rd.targetId); //撤销单对应的订单
                    if(rdTarget.dealVolume > 0)
                    {
                        rdTarget.state = OrderState.PartCancel;
                    }
                    else
                    {
                        rdTarget.state = OrderState.Cancel; //如果一点都没成交，显示全部撤销
                    }
                }

            }
            else
            {
                if (dl.volume > 0)
                {
                    rd.dealPrice = (rd.dealVolume * rd.dealPrice + dl.price * dl.volume) / (rd.dealVolume + dl.volume); //算平均价格
                    rd.dealVolume += dl.volume;
                    rd.dealTime = dl.time;
                    rd.count += dl.count;
                }
                
                if (rd.dealVolume == rd.quoteVolume)
                {
                    rd.state = OrderState.Fill;
                }
                else if(rd.dealVolume == 0)
                {
                    rd.state = OrderState.NotFill;
                }
                else
                {
                    rd.state = OrderState.PartFill;
                }
            }
           
        }

        public Record Find(Deal dl) // 通过交易所反馈的订单，找到对应的发送单
        {
            return orderDict[dl.id];
        }

        public bool IsOrderComplete(string code) //是否该股票有已发出，没有反馈的情况
        {
            List<string> tks = orderDict.Values.Where((x => x.code == code && x.state == OrderState.Send)).Select(x => x.code).ToList();
            if (tks.Count > 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        public bool IsAnyOrderBelongTheSameLeader(Follow fl)
        {
            List<string> tks = orderDict.Values.Where(x => x.code == fl.code && x.leader == fl.leader && x.leaderTime == fl.leaderTime).Select(x => x.code).ToList();
            if(tks.Count > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool IsContainCouterpartOrder(Follow fl) // 是否存在对应单，卖出时对应是否有相应的买单
        {
            // code 相同， leader相同， 成为小弟的时间也相同。
            List<Record> lrd =  orderDict.Values.Where(x => (x.leader == fl.leader) && (x.code == fl.code) && (x.beFollowTime == fl.time)).ToList();
            if (lrd.Count == 1)
            {
                if(lrd[0].state == OrderState.Fill)
                {
                    return true;
                }
                else if(lrd[0].state == OrderState.PartFill)
                {

                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if(lrd.Count == 0)
            {
                return false;
            }
            else
            {
                throw new Exception("there are redundant order ");
            }
            
        }

        public Record GetCounterpartOrder(Follow fl)
        {
            List<Record> lrd = orderDict.Values.Where(x => (x.leader == fl.leader) && (x.code == fl.code) && (x.beFollowTime == fl.time)).ToList();
            if (lrd.Count == 1)
            {
                return lrd[0];
            }
            else if (lrd.Count == 0)
            {
                return null;
            }
            else
            {
                throw new Exception("there are redundant order ");
            }
        }

        public Record GetCounterpartOrder(Record rd)
        {
            List<Record> lrd = orderDict.Values.Where(x => (x.leader == rd.leader) && (x.code == rd.code) && (x.beFollowTime == rd.beFollowTime) && 
            (x.type != OrderType.Cancel) && (x.side != rd.side)).ToList();
            if(lrd.Count == 1)
            {
                return lrd[0];
            }
            else if(lrd.Count == 0)
            {
                return null;
            }
            else
            {
                throw new Exception("there are redundant order");
            }
        }

        public Order BuildBuyOrder(Follow fl, int quotePos, int volume)
        {
            DateTime time = GetCurrentTime();
            Order od = new Order();
            od.code = fl.code;
            od.price = SimulateMarket.GetInstance().GetMarketSnapshot(fl.code).sell_px[quotePos-1]; //挂对手档位
            od.volume = volume;
            od.side = TradeSide.Buy;
            od.type = OrderType.Limit;
            od.id = od.code + fl.leader + fl.time.ToString("HHmmss") + ((int)od.type).ToString() + ((int)od.side).ToString();

            Record rd = new Record();
            rd.code = fl.code;
            rd.sector = fl.sect;
            rd.beFollowTime = fl.time;
            rd.count = 0;
            rd.orderId = od.id;
            rd.leader = fl.leader;
            rd.leaderTime = fl.leaderTime;
            rd.quotePrice = od.price;
            rd.quoteVolume = od.volume;
            rd.sendTime = time;
            rd.side = od.side;
            rd.state = OrderState.Send;
            rd.type = od.type;
            AddRecord(rd); //添加订单记录

            return od;
        }

        public Order BuildSellOrder(Follow fl, int quotePos, int volume)
        {
            DateTime time = GetCurrentTime();
            Order od = new Order();
            od.code = fl.code;
            od.price = SimulateMarket.GetInstance().GetMarketSnapshot(fl.code).buy_px[quotePos-1]; //挂对手档位
            od.volume = volume;
            od.side = TradeSide.Sell;
            od.type = OrderType.Limit;
            od.id = od.code + fl.leader + fl.time.ToString("HHmmss") + ((int)od.type).ToString() +((int)od.side).ToString();

            Record rd = new Record();
            rd.code = fl.code;
            rd.sector = fl.sect;
            rd.beFollowTime = fl.time;
            rd.count = 0;
            rd.orderId = od.id;
            rd.leader = fl.leader;
            rd.leaderTime = fl.leaderTime;
            rd.quotePrice = od.price;
            rd.quoteVolume = od.volume;
            rd.sendTime = time;
            rd.side = od.side;
            rd.state = OrderState.Send;
            rd.exitReason = fl.exitReason;
            rd.type = od.type;
            AddRecord(rd); //添加订单记录

            return od;
        }

        public Order BuildCancelOrder(Follow fl, string targetId) //其实fl都没必要，只需用targetId就行，但是为了打印的记录便于查找，记录了fl的code
        {
            DateTime time = GetCurrentTime();
            Order od = new Order();
            od.code = fl.code;
            od.price = 0;
            od.volume = 0;
            od.side = TradeSide.Buy; //这个无所谓
            od.type = OrderType.Cancel;
            od.id = od.code + fl.leader + fl.time.ToString("HHmmss") + ((int)od.type).ToString() + ((int)od.side).ToString();
            od.targetId = targetId;

            Record rd = new Record();
            rd.code = fl.code;
            rd.sector = fl.sect;
            rd.beFollowTime = fl.time;
            rd.count = 0;
            rd.orderId = od.id;
            rd.leader = fl.leader;
            rd.leaderTime = fl.leaderTime;
            rd.quotePrice = od.price;
            rd.quoteVolume = od.volume;
            rd.sendTime = time;
            rd.side = od.side;
            rd.state = OrderState.Send;
            rd.exitReason = fl.exitReason;
            rd.type = od.type;
            rd.targetId = targetId; //这个需要
            AddRecord(rd); //添加订单记录

            return od;
        }

        public List<ResStat> ResultStat()
        {
            List<ResStat> lrs = new List<ResStat>();
            List<Record> lrd = orderDict.Values.Where(x=>(x.side == TradeSide.Sell)&&((x.state == OrderState.Fill)||(x.state == OrderState.PartFill))).ToList();
            foreach(var rd in lrd)
            {
                Record rd_cpt = GetCounterpartOrder(rd);
                if (rd_cpt == null)
                {
                    continue;
                }
                ResStat rs = new ResStat();
                rs.code = rd_cpt.code;
                rs.leader = rd_cpt.leader;
                rs.sector = rd_cpt.sector;
                rs.enterSignalTime = rd_cpt.sendTime;
                rs.exitSignalTime = rd.sendTime;
                rs.durSignalTime = rs.exitSignalTime - rs.enterSignalTime;
                rs.buyDealTime = rd_cpt.dealTime;
                rs.sellDealTime = rd.dealTime;
                rs.durDealTime = rs.sellDealTime - rs.buyDealTime;
                rs.buyPrice = rd_cpt.dealPrice;
                rs.sellPrice = rd.dealPrice;
                rs.ret = (rs.sellPrice - rs.buyPrice) / rs.buyPrice * 10000;
                lrs.Add(rs);
            }
            return lrs;
        }
        public Dictionary<string,string> GetName()
        {
            return SimulateMarket.GetInstance().GetName();
        }
        

        public void Save(string path)
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            var nameDict = GetName();

            string stat_arg_str = StrategyPara.get_follow_pair_arg_str();
            string backtest_arg_str = StrategyPara.get_backtest_arg_str();

            string recordPath = String.Format(@"{0}\{1}.OrderRecord.{2}_{3}.csv", path, DateUtils.ToString(GetCurrentTime()), stat_arg_str, backtest_arg_str);
            List<Record> orderList = orderDict.Values.OrderBy(x => x.code).Select(x => { x.name = nameDict[x.code]; x.leaderName = nameDict[x.leader]; return x; }).ToList();
            CsvHandler.ListSave2CSV(recordPath, orderList);

            List<ResStat> lrs = ResultStat().OrderBy(x => x.code).Select(x => { x.name = nameDict[x.code]; x.leaderName = nameDict[x.leader]; return x; }).ToList(); 
            string statPath = String.Format(@"{0}\{1}.ResultStat.{2}_{3}.csv", path, DateUtils.ToString(GetCurrentTime()), stat_arg_str, backtest_arg_str);
            CsvHandler.ListSave2CSV(statPath, lrs);
        }
    }
        
    public class Record
    {
        public string orderId;
        public string code;
        public string name;
        public string leader;
        public string leaderName;
        public string sector;
        public DateTime leaderTime; // 跟随的龙头成为龙头的时间
        public DateTime beFollowTime; // 成为跟随者的时间
        public DateTime sendTime; // 发单时间
        public DateTime dealTime; // 成交时间
        public float quotePrice;
        public float dealPrice;
        public int quoteVolume;
        public int dealVolume;
        public TradeSide side; // buy or sell
        public OrderType type;
        public int count; //已成交笔数
        public OrderState state; // 订单状态
        public ExitReason exitReason; //退出原因
        public string targetId; // 如果发出的单是撤销单，该单对应的要撤销的订单编号
        public Record()
        {
            targetId = "";
            dealPrice = 0f;
            dealVolume = 0;
            state = OrderState.NotSend;
            exitReason = ExitReason.notExit; //默认值
            count = 0;
        }
    }

    public class ResStat
    {
        public string code;
        public string name;
        public string leader;
        public string leaderName;
        public string sector;
        public DateTime enterSignalTime;
        public DateTime exitSignalTime;
        public TimeSpan durSignalTime;
        public DateTime buyDealTime;
        public DateTime sellDealTime;
        public TimeSpan durDealTime;
        public float buyPrice;
        public float sellPrice;
        public float ret;
    }
}
